package top.techqi.hamtools.func

import android.os.Bundle
import android.support.annotation.CallSuper
import android.support.v7.widget.SearchView
import android.util.SparseArray
import android.view.*
import com.jakewharton.rxbinding2.support.v7.widget.RxSearchView
import com.raizlabs.android.dbflow.kotlinextensions.get
import com.raizlabs.android.dbflow.sql.language.CursorResult
import com.raizlabs.android.dbflow.structure.BaseModel
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.fragment_vernier.*
import top.techqi.droidbdf.pangu.base.BaseFragment
import top.techqi.droidbdf.pangu.util.LogV
import top.techqi.droidbdf.widget.recycler.RecyclerAdapter
import top.techqi.hamtools.R
import java.lang.ref.SoftReference
import java.util.concurrent.TimeUnit

@Suppress("MemberVisibilityCanBePrivate")
abstract class VernierFragment : BaseFragment() {
    private var disposer = CompositeDisposable()

    open val filtable: Boolean = true
    open val subtitle: String? = null
    protected val adapter = RecyclerAdapter()

    protected lateinit var seacher: SearchView

    @CallSuper
    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        if (filtable) setHasOptionsMenu(true)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_vernier, container, false)
    }

    override fun onViewCreated(view: View, state: Bundle?) {
        super.onViewCreated(view, state)
        vernier.adapter = adapter

        requestCursor()
    }

    override fun onDestroy() {
        disposer.clear()
        super.onDestroy()
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        if (filtable) {
            inflater.inflate(R.menu.search, menu)
            seacher = menu.findItem(R.id.search).actionView as SearchView
            RxSearchView.queryTextChanges(seacher)
                    .debounce(200, TimeUnit.MILLISECONDS)
                    .map(CharSequence::toString)
                    .subscribe { requestCursor(it) }
                    .autoDispose()
        }
    }

    abstract fun queryCursor(keyword: String = ""): Single<out CursorResult<out BaseModel>>

    open fun mapCursor(model: BaseModel, keyword: String): Any = model

    protected fun requestCursor(keyword: String = "") {
        queryCursor(keyword)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ cursor ->
                    adapter.setItems(object : RecyclerAdapter.Provider {
                        val cache = SparseArray<SoftReference<Any>>()
                        override val count = cursor.count.toInt()
                        override operator fun get(position: Int) =
                                cache[position]?.get().let {
                                    if (it == null) {
                                        val item = mapCursor(cursor[position], keyword)
                                        cache.put(position, SoftReference(item))
                                        item
                                    } else it
                                }
                    })
                }, {
                    @Suppress("USELESS_CAST")
                    LogV.w(TAG as? String, it)
                })
                .autoDispose()
    }

    protected fun Disposable?.autoDispose() {
        this?.let { disposer.add(it) }
    }
}